package cemp.service;

import cemp.common.dto.request.StockLoginRequestDto;
import cemp.common.dto.request.StockSysUserRequestDto;
import cemp.constant.WxConstant;
import cemp.dto.ro.LoginResponse;
import cemp.entity.StockSysUser;
import cemp.jwt.JwtCommonUser;
import cemp.jwt.JwtTokenUtil;
import cemp.mapper.StockSysUserMapper;
import cemp.redis.constant.RedisKey;
import cemp.redis.util.RedisUtils;
import cemp.shiro.OAuth2Token;
import cemp.util.StockHttpUtil;
import cemp.util.UrlUtils;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.common.http.HttpUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.BeanUtils;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import static cemp.common.constant.StockCommonConstant.*;

@RequiredArgsConstructor
@Slf4j
@Service
public class StockSysUserService {

    @Resource
    private final StockSysUserMapper stockSysUserMapper;
    @Resource
    private final RedisUtils redisUtils;
    @Resource
    private final RestTemplate restTemplate;

    /**
     * 生成盐 每个用户的salt都不一样
     * @return
     */
    private String generateSalt(){
        byte[] salt = new byte[16];
        new SecureRandom().nextBytes(salt);
        return Base64.getEncoder().encodeToString(salt);

    }

    private StockSysUser getByName(String username){
        return stockSysUserMapper.getByName(username);
    }


    public LoginResponse login(StockLoginRequestDto login) throws Exception {
        LoginResponse response = new LoginResponse();
        //匹配数据库
        StockSysUser user = getByName(login.getUsername());
        //对password加密并和数据库比较
        boolean passRight = user != null && user.getPassword().equals(new Sha256Hash(login.getPassword(), user.getSalt()).toHex()) ;
        //生成jwt token
        if(passRight){
            JwtCommonUser commonUser = new JwtCommonUser();
            commonUser.setOpenid(user.getOpenid());
            commonUser.setUserId(Long.valueOf(user.getId()));
            String token = JwtTokenUtil.generateToken(commonUser);
            OAuth2Token tk = new OAuth2Token(token);
            //维护redis
            String key = RedisKey.STOCK_AUTH_USER.concat(user.getId().toString());
            redisUtils.set(key,token,JwtTokenUtil.T_MILS_DAY);
            if("shiro".equals(login.getLoginType())){
                //执行shiro登录,
                SecurityUtils.getSubject().login(tk);
            }
            return LoginResponse.builder().phoneNumber(user.getMobile()).token(token).name(user.getRealname()).build();
        }
        return null;
    }

    public String ssLogin(StockLoginRequestDto login) throws Exception {
        //匹配数据库
        StockSysUser user = getByName(login.getUsername());
        //对password加密并和数据库比较
        boolean passRight = user != null && user.getPassword().equals(new Sha256Hash(login.getPassword(), user.getSalt()).toHex()) ;
        //生成jwt token
        if(passRight){
            JwtCommonUser commonUser = new JwtCommonUser();
            commonUser.setOpenid(user.getOpenid());
            commonUser.setUserId(Long.valueOf(user.getId()));
            String token = JwtTokenUtil.generateToken(commonUser);
            OAuth2Token tk = new OAuth2Token(token);
            //维护redis
            String key = RedisKey.STOCK_AUTH_USER.concat(user.getId().toString());
            redisUtils.set(key,token,JwtTokenUtil.T_MILS_DAY);
            //执行shiro登录,
            return token;
        }
        return null;
    }

    /**
     * 注册
     * @param user
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public void register(StockSysUserRequestDto user) throws InvocationTargetException, IllegalAccessException {
        StockSysUser userEntity = new StockSysUser();
        BeanUtils.copyProperties(user,userEntity);
        //password加密
        String salt =generateSalt();
        String parsedPWD = new Sha256Hash(user.getPassword(), salt).toHex();
        userEntity.setSalt(salt);
        userEntity.setPassword(parsedPWD);
        userEntity.setOpenid(UUID.randomUUID().toString());     //??
        stockSysUserMapper.insert(userEntity);
    }


    /**
     * 手机号一键登录
     * @param login
     * @return
     */
    public LoginResponse phoneLogin(StockLoginRequestDto login) throws Exception {
        //根据 appid和secret去换取临时的accessToken
        Map<String,String> param1 = new HashMap<>();
        param1.put("grant_type","client_credential");
        param1.put("appid","wx865cbd70bc607872");
        param1.put("secret","6cd81ea2a85a0929addbc874550ac324");
        String url1 = UrlUtils.urlJoin(WxConstant.URL_WX_GET_ACCESS_TOKEN,param1);
        String accessTokenResponse = restTemplate.getForObject(url1,String.class);
        String accessToken = JSONObject.parseObject(accessTokenResponse).getString("access_token");
        //accessToken和 phoneCode 换手机号
        Map<String,String> param2 = new HashMap<>();
        param2.put("access_token",accessToken);
        String url2 = UrlUtils.urlJoin(WxConstant.URL_WX_GET_PHONE,param2);
        Map<String,String> entity = new HashMap<>();
        entity.put("code",login.getPhoneCode());
        String getPhoneResponse = restTemplate.postForObject(url2,entity,String.class);
        JSONObject j = JSONObject.parseObject(getPhoneResponse);
        String phoneNumber = j.getString("errcode").equals("0")?  j.getJSONObject("phone_info").getString("phoneNumber") : null;

        //判断用户是否存在 登录or 注册
        StockSysUser user =  stockSysUserMapper.getByPhone(phoneNumber);
        if(user == null){
            //注册流程
            StockSysUser userInput = new StockSysUser();
            userInput.setOpenid(login.getOpenId());
            user.setUsername(phoneNumber);
            user.setMobile(phoneNumber);
//            user.setRealname();
            stockSysUserMapper.insert(userInput);

        }else{
            //登录流程
            JwtCommonUser commonUser = new JwtCommonUser();
            commonUser.setOpenid(user.getOpenid());
            commonUser.setUserId(Long.valueOf(user.getId()));
            String token = JwtTokenUtil.generateToken(commonUser);

            //维护redis
            //String key = RedisKey.STOCK_AUTH_USER.concat(user.getId().toString());
            //redisUtils.set(key,token,JwtTokenUtil.T_MILS_DAY);
            return LoginResponse.builder().phoneNumber(phoneNumber).token(token).build();

        }
        return null;
    }
}
